技术经验 • dingxiao • 阅读数:5676 • 2019年7月31日 09:31
#####
段式液晶以超低功耗、价格低廉、驱动便利等特点,使它成为众多消费产品显示的首选。
HOLTEK公司的HT1621是驱动段式液晶常用的芯片,它是一款128 点内存映象和多功能的LCD驱动器。HT1621 的软件配置特性使它适用于多种LCD应用场合包括LCD模块和显示子系统,用于连接主控制器和HT1621的管脚只需4 或5 pin,HT1621 还提供节电命令用于降低系统功耗。
TB买了一块段式液晶已配置HT1621。
驱动HT1621选择了手头上有的几块ESP8266,ESP8266驱动HT1621挺适合,测试连线:
D5--->CS
D6--->WR
D7--->DA
供电:3.3V
驱动调试参考网址:
1)https://github.com/anxzhu/segment-lcd-with-ht1621
2)https://github.com/5N44P/ht1621-7-seg
在Arduion软件库中下载HT1621库(HT1621.cpp和HT1621.h),该库的维护者是参考网址中的第2个作者,但问题是下载的HT1621驱动并不能直接应用到该段式液晶上,需要对驱动程序进行优化。
对HT1621.cpp的优化,优化点已注释统一标识:@-DX-Test-20190730
#include <Arduino.h>
#include "HT1621.h"
HT1621::HT1621(){
_buffer[0] = 0x00;
_buffer[1] = 0x00;
_buffer[2] = 0x00;
_buffer[3] = 0x00;
}
void HT1621::begin(int cs_p,int wr_p,int data_p,int backlight_p)
{
pinMode(cs_p, OUTPUT);
pinMode(wr_p, OUTPUT);
pinMode(data_p, OUTPUT);
pinMode(backlight_p, OUTPUT);
_cs_p=cs_p;
_wr_p=wr_p;
_data_p=data_p;
_backlight_p=backlight_p;
_backlight_en=true;
config();
}
void HT1621::begin(int cs_p,int wr_p,int data_p)
{
pinMode(cs_p, OUTPUT);
pinMode(wr_p, OUTPUT);
pinMode(data_p, OUTPUT);
_cs_p=cs_p;
_wr_p=wr_p;
_data_p=data_p;
_backlight_en = false;
config();
}
void HT1621::wrDATA(unsigned char data, unsigned char cnt) {
unsigned char i;
for (i = 0; i < cnt; i++) {
digitalWrite(_wr_p, LOW);
delayMicroseconds(4);
if (data & 0x80) {
digitalWrite(_data_p, HIGH);
}
else
{
digitalWrite(_data_p, LOW);
}
digitalWrite(_wr_p, HIGH);
delayMicroseconds(4);
data <<= 1;
}
}
void HT1621::wrclrdata(unsigned char addr, unsigned char sdata)
{
addr <<= 2;
digitalWrite(_cs_p, LOW);
wrDATA(0xa0, 3);
wrDATA(addr, 6);
wrDATA(sdata, 8);
digitalWrite(_cs_p, HIGH);
}
void HT1621::display()
{
wrCMD(LCDON);
}
void HT1621::noDisplay()
{
wrCMD(LCDOFF);
}
void HT1621::wrone(unsigned char addr, unsigned char sdata)
{
addr <<= 2;
digitalWrite(_cs_p, LOW);
wrDATA(0xa0, 3);
wrDATA(addr, 6);
wrDATA(sdata, 8);
digitalWrite(_cs_p, HIGH);
}
void HT1621::backlight()
{
if (_backlight_en)
digitalWrite(_backlight_p, HIGH);
delay(1);
}
void HT1621::noBacklight()
{
if(_backlight_en)
digitalWrite(_backlight_p, LOW);
delay(1);
}
void HT1621::wrCMD(unsigned char CMD) { //100
digitalWrite(_cs_p, LOW);
wrDATA(0x80, 4);
wrDATA(CMD, 8);
digitalWrite(_cs_p, HIGH);
}
void HT1621::config()
{
wrCMD(BIAS);
wrCMD(RC256);
wrCMD(SYSDIS);
wrCMD(WDTDIS1);
wrCMD(SYSEN);
wrCMD(LCDON);
}
void HT1621::wrCLR(unsigned char len) {
unsigned char addr = 0;
unsigned char i;
for (i = 0; i < len; i++) {
wrclrdata(addr, 0x00);
addr = addr + 2;
}
}
void HT1621::setBatteryLevel(int level) {
// zero out the previous (otherwise the or couldn't be possible)
_buffer[0] &= 0x7F;
_buffer[1] &= 0x7F;
_buffer[2] &= 0x7F;
switch(level){
case 3: // battery on and all 3 segments
_buffer[0] |= 0x80;
case 2: // battery on and 2 segments
_buffer[1] |= 0x80;
case 1: // battery on and 1 segment
_buffer[2] |= 0x80;
case 0: // battery indication off
default:
break;
}
update();
}
void HT1621::clear(){
wrCLR(16);
}
/*******************************以下函数需要根据LCD原理图进行修改*****
DX
1-->可以先使用wrone函数进行测试,测试的主要目的是确定数值显示的正确性
*************************************************/
void HT1621::update(){ // takes the buffer and puts it straight into the driver
// the buffer is backwards with respect to the lcd. could be improved
wrone(0, _buffer[0]);
wrone(2, _buffer[1]);
wrone(4, _buffer[2]);
wrone(6, _buffer[3]);
}
void HT1621::print(long num){
if(num > 999999) // basic checks
num = 999999; // clip into 999999
if(num < -99999) // basic checks
num = -99999; // clip into -99999
/*char localbuffer[7]; //buffer to work with in the function
snprintf(localbuffer,7, "%6li", num); // convert the decimal into string DX-根据LCD原理图修改-20190730*/
char localbuffer[5]; //buffer to work with in the function
snprintf(localbuffer,5, "%4li", num); // convert the decimal into string
/*for(int i=0; i<6; i++){ -DX-根据LCD原理图修改-20190730 */
for(int i=0; i<4; i++){
/*_buffer[i] &= 0x80; // mask the first bit, used by batter and decimal point*/
_buffer[i] &= 0x10; // mask the first bit, used by batter and decimal point
switch(localbuffer[i]){ // map the digits to the seg bits
//@-DX-根据LCD原理图修改-20190730
case '0':
_buffer[i] |= 0xeb;
break;
case '1':
_buffer[i] |= 0x0a;
break;
case '2':
_buffer[i] |= 0xad;
break;
case '3':
_buffer[i] |= 0x8f;
break;
case '4':
_buffer[i] |= 0x4e;
break;
case '5':
_buffer[i] |= 0xc7;
break;
case '6':
_buffer[i] |= 0xe7;
break;
case '7':
_buffer[i] |= 0x8a;
break;
case '8':
_buffer[i] |= 0xef;
break;
case '9':
_buffer[i] |= 0xcf;
break;
case '-':
_buffer[i] |= 0x04;
break;
}
}
update();
}
void HT1621::print(float num){
// could be smarter and actually check how many
// non zeros we have in the decimals
print(num, 3);
}
void HT1621::print(float num, int precision){
if(num > 999999) // basic checks
num = 999999; // clip into 999999
if(num < -99999) // basic checks
num = -99999; // clip into -99999
if(precision > 3 && num > 0)
precision = 3; // if positive max precision allowed = 3
else if(precision > 2 && num < 0)
precision = 2;// if negative max precision allowed = 2
if(precision < 0)
precision = 0; // negative precision?!
long ingegerpart;
ingegerpart = ((long)(num*pow(10,precision)));
print(ingegerpart); // draw the integerized number
setdecimalseparator(precision); // draw the decimal point
update();
}
void HT1621::setdecimalseparator(int decimaldigits) {
// zero out the eight bit
/*_buffer[3] &= 0x7F;
_buffer[4] &= 0x7F;
_buffer[5] &= 0x7F; DX-根据LCD原理图修改-20190730*/
_buffer[3] &= 0xeb;
_buffer[4] &= 0xeb;
_buffer[5] &= 0xeb;
if( decimaldigits <= 0 || decimaldigits > 3){
return;
}
/*_buffer[6-decimaldigits] |= 0x80; DX-根据LCD原理图修改-20190730*/
_buffer[6-decimaldigits] |= 0x10;
}
char * HT1621::floatToString(char * outstr, float value, int places, int minwidth=0, bool rightjustify=false)
{
int digit;
float tens = 0.1;
int tenscount = 0;
int i;
float tempfloat = value;
int c = 0;
int charcount = 1;
int extra = 0;
float d = 0.5;
if (value < 0)
d *= -1.0;
for (i = 0; i < places; i++)
d/= 10.0;
tempfloat += d;
if (value < 0)
tempfloat *= -1.0;
while ((tens * 10.0) <= tempfloat) {
tens *= 10.0;
tenscount += 1;
}
if (tenscount > 0)
charcount += tenscount;
else
charcount += 1;
if (value < 0)
charcount += 1;
charcount += 1 + places;
minwidth += 1;
if (minwidth > charcount){
extra = minwidth - charcount;
charcount = minwidth;
}
if (extra > 0 and rightjustify) {
for (int i = 0; i< extra; i++) {
outstr[c++] = ' ';
}
}
if (value < 0)
outstr[c++] = '-';
if (tenscount == 0)
outstr[c++] = '0';
for (i=0; i< tenscount; i++) {
digit = (int) (tempfloat/tens);
itoa(digit, &outstr[c++], 10);
tempfloat = tempfloat - ((float)digit * tens);
tens /= 10.0;
}
if (places > 0)
outstr[c++] = '.';
for (i = 0; i < places; i++) {
tempfloat *= 10.0;
digit = (int) tempfloat;
itoa(digit, &outstr[c++], 10);
// once written, subtract off that digit
tempfloat = tempfloat - (float) digit;
}
if (extra > 0 and not rightjustify) {
for (int i = 0; i< extra; i++) {
outstr[c++] = ' ';
}
}
outstr[c++] = '\0';
return outstr;
}
void HT1621::dispnum_dx(float num){/*传入显示的数据,最高位为小数点和电量显示,显示数据为0.001-99999.9*/
char buffer1[12];
floatToString(buffer1,num,4);
String buffer=buffer1;
int dpposition;
dpposition=buffer.indexOf('.');/*寻找小数点位置 取前七位 因为最多显示七位*/
/*为4 整数 如1234.
//3 一位小数 123.4
//2 两位小数 12.34
//1 三位小数 1.234 */
/*Test = String(dpposition);*/
unsigned int i;
for(i=0;i<5;i++){
if(buffer[i]=='0'){
buffer[i]=0xeb;
}
else if(buffer[i]=='1') {
buffer[i]=0x0a;
}
else if (buffer[i]=='2'){
buffer[i]=0xad;
}
else if (buffer[i]=='3'){
buffer[i]=0x8f;
}
else if(buffer[i]=='4') {
buffer[i]=0x4e;
}
else if(buffer[i]=='5') {
buffer[i]=0xc7;
}
else if(buffer[i]=='6') {
buffer[i]=0xe7;
}
else if (buffer[i]=='7'){
buffer[i]=0x8a;
}
else if (buffer[i]=='8'){
buffer[i]=0xef;
}
else if (buffer[i]=='9'){
buffer[i]=0xcf;
}
else if (buffer[i]=='.'){
buffer[i]=0x10;
}
}
switch (dpposition){
case 3: /*123.4*/
_buffer[0] = buffer[0];
_buffer[1] = buffer[1];
_buffer[2] = buffer[2];
_buffer[3] = buffer[4]|0x10;
break;
case 2: /*12.34*/
_buffer[0] = buffer[0];
_buffer[1] = buffer[1];
_buffer[2] = buffer[3]|0x10;
_buffer[3] = buffer[4];
break;
case 1:/*1.234*/
_buffer[0] = buffer[0];
_buffer[1] = buffer[2]|0x10;
_buffer[2] = buffer[3];
_buffer[3] = buffer[4];
break;
default:
break;
}
update();
}
1)HT1621作为LCD的驱动芯片,需要知晓芯片与LCD的连接原理图,根据原理图列出需要显示字符的编码。
2)在测试初期可以先使用lcd.wrone(0,0xc7)函数对一个显示区域进行调试,这样可以快速理解显示规则,对后期优化驱动提供较好的实践支持。